package org.ebookdroid.ui.opds.adapters; import org.ebookdroid.common.cache.CacheManager; import org.ebookdroid.common.cache.ThumbnailFile; import org.ebookdroid.opds.model.Book; import org.ebookdroid.opds.model.Feed; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import java.io.File; import java.io.FileInputStream; import java.util.ConcurrentModificationException; import org.emdev.ui.tasks.AsyncTask; import org.emdev.utils.LengthUtils; import org.emdev.utils.concurrent.Flag; final class LoadThumbnailTask extends AsyncTask<Feed, Book, String> { private final OPDSAdapter adapter; private final Flag stopped = new Flag(); LoadThumbnailTask(OPDSAdapter adapter) { this.adapter = adapter; } public void stop() { stopped.set(); } @Override protected String doInBackground(final Feed... params) { if (LengthUtils.isEmpty(params)) { return null; } for (final Feed feed : params) { if (feed == null) { continue; } while (true) { try { for (final Book book : feed.books) { if (stopped.get() || adapter.currentFeed != feed) { return null; } loadBookThumbnail(book); publishProgress(book); } break; } catch (ConcurrentModificationException ex) { if (stopped.get() || adapter.currentFeed != feed) { return null; } // else repeat scanning } } } return null; } @Override protected void onPostExecute(final String result) { adapter.notifyDataSetInvalidated(); } @Override protected void onProgressUpdate(final Book... books) { boolean inCurrent = false; for (final Book book : books) { inCurrent |= book.parent == adapter.currentFeed; } if (inCurrent) { adapter.notifyDataSetInvalidated(); } } protected void loadBookThumbnail(final Book book) { if (book.thumbnail == null) { return; } final ThumbnailFile thumbnailFile = CacheManager.getThumbnailFile(book.id); if (thumbnailFile.exists()) { return; } try { final File file = adapter.client.loadFile(book.parent, book.thumbnail); if (file == null) { return; } final Options opts = new Options(); opts.inPreferredConfig = Bitmap.Config.ARGB_8888; opts.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(file), null, opts); opts.inSampleSize = getScale(opts, 200, 200); opts.inJustDecodeBounds = false; final Bitmap image = BitmapFactory.decodeStream(new FileInputStream(file), null, opts); if (image != null) { thumbnailFile.setImage(image); image.recycle(); } } catch (final Throwable ex) { ex.printStackTrace(); } } protected int getScale(final Options opts, final float requiredWidth, final float requiredHeight) { int scale = 1; int widthTmp = opts.outWidth; int heightTmp = opts.outHeight; while (true) { if (widthTmp / 2 < requiredWidth || heightTmp / 2 < requiredHeight) { break; } widthTmp /= 2; heightTmp /= 2; scale *= 2; } return scale; } }